﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO;
using System.Xml;
using System.Runtime.Serialization;
using Microsoft.Win32;

namespace tscsclassgen
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        private bool isDirty = false;
        private string fileName = null;
        private List<ClassDef> classes = new List<ClassDef>();
        private ClassDef currentTargetClass { get { return (ClassDef)(ListBoxClasses.SelectedItem); } }

        public MainWindow()
        {
            InitializeComponent();
            addTypeList(this.ComboBoxInheritFrom);
            this.ComboBoxInheritFrom.SelectedIndex = 0;
        }

        private void MenuExit_Click(object sender, RoutedEventArgs e)
        {
            this.Close();
        }

        private void MenuSaveAs_Click(object sender, RoutedEventArgs e)
        {
            saveas();
        }

        private void MenuSave_Click(object sender, RoutedEventArgs e)
        {
            save();
        }

        private void MenuOpen_Click(object sender, RoutedEventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.FileName = "";
            ofd.DefaultExt = ".xml";
            ofd.Filter = "XML documents (.xml)|*.xml";
            if (ofd.ShowDialog() == true) load(ofd.FileName);
        }

        private void MenuNew_Click(object sender, RoutedEventArgs e)
        {
            classes.Clear();
            fileName = null;
            update();
        }

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            if (!isDirty) return;
            var r = MessageBox.Show("Data is not saved, Do you want to save them before close?", this.Title, MessageBoxButton.YesNoCancel);
            if (r == MessageBoxResult.Yes) save();
            if (r == MessageBoxResult.Cancel) e.Cancel = true;
        }

        private void update()
        {
            ListBoxClasses.Items.Clear();
            foreach (var item in classes)
            {
                ListBoxClasses.Items.Add(item);
            }



            // TBW update display
        }

        private void load(string filename)
        {
            var ds = new DataContractSerializer(classes.GetType());
            using (TextReader sw = File.OpenText(filename))
            {
                using (var xw = XmlReader.Create(sw))
                {
                    classes = (List<ClassDef>)ds.ReadObject(xw, false);
                }
            }
            fileName = filename;
            update();
        }

        private void save(string filename)
        {
            var ds = new DataContractSerializer(classes.GetType());
            using (TextWriter sw = new StringWriter())
            {
                using (var xw = XmlWriter.Create(sw))
                {
                    ds.WriteObject(xw, classes);
                }
                if (File.Exists(filename))
                {
                    string temp = System.IO.Path.ChangeExtension(filename, "$$$");
                    string bak = System.IO.Path.ChangeExtension(filename, "bak");
                    File.WriteAllText(temp, sw.ToString());
                    File.Replace(temp, filename, bak);
                }
                else
                {
                    File.WriteAllText(filename, sw.ToString());
                }
            }
            fileName = filename;
        }

        private void save()
        {
            if (fileName == null) saveas();
            else save(fileName);
        }

        private void saveas()
        {
            var sfd = new SaveFileDialog();
            sfd.FileName = fileName ?? "";
            sfd.DefaultExt = ".xml";
            sfd.Filter = "XML documents (.xml)|*.xml";
            if (sfd.ShowDialog() == true) save(sfd.FileName);
        }

        private void EditInternalTypes_Click(object sender, RoutedEventArgs e)
        {

        }

        private void ButtonNewClass_Click(object sender, RoutedEventArgs e)
        {
            int n = 0;
            string newname;
            for (; ; )
            {
                newname = "MyClass" + n.ToString();
                if (classes.All(c => c.ThisClassName != newname)) break;
                n++;
            }
            var newitem = new ClassDef();
            newitem.ThisClassName = newname;
            classes.Add(newitem);
            update();
            this.ListBoxClasses.SelectedIndex = this.ListBoxClasses.Items.Count - 1;
            isDirty = true;
        }

        private void ListBoxClasses_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            updateClass(currentTargetClass);
        }

        private IEnumerable<string> allTypes()
        {
            var list = new List<string>();
            list.AddRange(PredefinedTypes.Names.Select(c => c.TypeScriptName));
            var item = currentTargetClass;
            if (item != null && item.ExtraNames != null) list.AddRange(item.ExtraNames.Select(c => c.TypeScriptName));
            list.AddRange(classes.Select(c => c.ThisClassName));
            return list;
        }

        private void addTypeList(ComboBox cb)
        {
            cb.Items.Clear();
            foreach (var item in allTypes()) cb.Items.Add(item);
        }

        private void updateClass(ClassDef item)
        {
            ListViewMembers.Items.Clear();
            //System.Diagnostics.Debug.Assert(ListViewMembers.Items.Count == 0);
            if (item == null)
            {
                TextBoxClassName.Text = "";
                ComboBoxInheritFrom.Text = "";
            }
            else
            {
                TextBoxClassName.Text = item.ThisClassName;
                addTypeList(this.ComboBoxInheritFrom);
                if (string.IsNullOrWhiteSpace(item.SuperClassName)) ComboBoxInheritFrom.SelectedIndex = 0;
                else ComboBoxInheritFrom.Text = item.SuperClassName;
                foreach (var item02 in item.Members)
                {
                    var item2 = item02;
                    var listviewitem = new ListViewItem();
                    var sp = new StackPanel();
                    sp.Orientation = Orientation.Horizontal;
                    var tb = new TextBox();
                    tb.Text = item2.MemberName;
                    tb.Width = 100;
                    tb.TextChanged += (sender, evt) =>
                    {
                        item2.MemberName = tb.Text;
                        isDirty = true;
                    };
                    sp.Children.Add(tb);
#if USE_COMBO
                    var cb = new ComboBox();
                    addTypeList(cb);
                    cb.IsEditable = true;
                    cb.IsDropDownOpen = true;
                    cb.Text = item2.TypeName;
                    cb.Width = 100;
                    cb.SelectionChanged += (sender, evt) =>
                    {
                        item2.TypeName = cb.Text;
                        isDirty = true;
                    };
                    sp.Children.Add(cb);
#else
                    var lbl = new TextBlock();
                    lbl.Text = item2.TypeName;
                    lbl.Width = 100;
                    sp.Children.Add(lbl);
                    var button = new Button();
                    button.Content = "...";
                    button.Click += (sender, evt) =>
                    {
                        var alt = new AlternativeTypeSelectorDialog(allTypes());
                        alt.Owner = this;
                        var r = alt.ShowDialog();
                        if (r != true) return;
                        item2.TypeName = alt.Selection;
                        lbl.Text = alt.Selection;
                        isDirty = true;
                    };
                    button.Margin = new Thickness(0,0,5,0);
                    sp.Children.Add(button);
#endif
                    var del = new Button();
                    del.Content = "Delete";
                    del.Click += (sender, evt) =>
                        {
                            var r = MessageBox.Show("Do you really want to delete this member?", this.Title, 
                                MessageBoxButton.YesNo);
                            if (r != MessageBoxResult.Yes) return;
                            currentTargetClass.Members.Remove(item2);
                            updateClass(currentTargetClass);
                            isDirty = true;
                        };
                    sp.Children.Add(del);
                    listviewitem.Content = sp;
                    ListViewMembers.Items.Add(listviewitem);
                }
            }
        }

        private void ButtonAddNewMember_Click(object sender, RoutedEventArgs e)
        {
            var item = currentTargetClass;
            if (item == null) return;
            var mem = new MemberDef();
            int n = 0;
            string newname;
            for (; ; )
            {
                newname = "YourName" + n.ToString();
                if (item.Members.All(c => c.MemberName != newname)) break;
                n++;
            }
            mem.MemberName = newname;
            mem.TypeName = "Object";
            item.Members.Add(mem);
            updateClass(item);
            ListViewMembers.SelectedIndex = ListViewMembers.Items.Count - 1;
            isDirty = true;
        }

        private void ComboBoxInheritFrom_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            var item = currentTargetClass;
            if (item == null) return;
            if (ComboBoxInheritFrom.SelectedItem != null) item.SuperClassName = (string)ComboBoxInheritFrom.SelectedItem;
            isDirty = true;
        }

        private void TextBoxClassName_TextChanged(object sender, TextChangedEventArgs e)
        {
            var item = currentTargetClass;
            if (item == null) return;
            item.ThisClassName = TextBoxClassName.Text;
            isDirty = true;
        }

        private void ButtonGenerate_Click(object sender, RoutedEventArgs e)
        {
            var map = PredefinedTypes.Names;
            var dlg = new ResultDialog(classes, map);
            dlg.Owner = this;
            dlg.ShowDialog();
        }

        private void ButtonRemoveClass_Click(object sender, RoutedEventArgs e)
        {
            var r = MessageBox.Show("Do you really want to delete this class?", this.Title,
                MessageBoxButton.YesNo);
            if (r != MessageBoxResult.Yes) return;
            classes.Remove(currentTargetClass);
            update();
            isDirty = true;
        }
    }
}
